﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using Quartz.Impl;

namespace goAlarmsCS
{
    public sealed class QuartzAlarmScheduler : IAlarmScheduler
    {
        #region CTORs, fields, and properties

        private Type _alarmJobType = typeof(alarmJob);

        private QuartzAlarmScheduler()
        {
            if (_quartzScheduler == null)
            { 
            ISchedulerFactory factory = new StdSchedulerFactory();
            _quartzScheduler = factory.GetScheduler();
            _quartzScheduler.Start();
            }
        }

        private static QuartzAlarmScheduler _instance;
        public static QuartzAlarmScheduler Instance()
        {
            if (_instance == null)
            {
                _instance = new QuartzAlarmScheduler();
                return _instance;
            }
            else
            {
                return _instance;
            }
        }

        private Dictionary<string, Alarm> _alarmList=new Dictionary<string,Alarm>();
        public Dictionary<string, Alarm> AlarmList
        {
            get
            {
                return _alarmList;
            }
        }

        private IScheduler _quartzScheduler;
        public IScheduler QuartzScheduler
        {
            get
            {
                return _quartzScheduler;
            }
        }

        #endregion

        #region AlarmScheduler Members

        public void Startup()
        {
            if (_instance == null)
            {
                _instance = new QuartzAlarmScheduler();
            }
        }

        public void Shutdown()
        {
            if (_quartzScheduler != null)
            {
                _quartzScheduler.Shutdown(false);
                _quartzScheduler = null;
            }
            _instance = null;
        }

        private JobDetail GetJobDetail(Alarm alarm)
        {
            return new JobDetail(alarm.Name, alarm.Group, _alarmJobType, true, false, false);
            //return new JobDetail("MyJob", alarm.Group, _alarmJobType, true, false, false);
        }

        public void AddTrigger(Alarm alarm)
        {
            if (!AlarmList.ContainsKey(alarm.Name))
            {
                AlarmList.Add(alarm.Name, alarm);
                Trigger trigger = (Trigger)alarm.CreateTriggerFunction(new CreateTriggerArgs(alarm.NextTriggerTime, alarm.Frequency, alarm.Name, alarm.Group));
                _quartzScheduler.ScheduleJob(GetJobDetail(alarm), (Trigger)trigger);
                //_quartzScheduler.ScheduleJob((Trigger)trigger);
            }
            else 
            {
                _quartzScheduler.UnscheduleJob(alarm.Name, alarm.Group);
                Trigger trigger = (Trigger)alarm.CreateTriggerFunction(new CreateTriggerArgs(alarm.NextTriggerTime, alarm.Frequency, alarm.Name, alarm.Group));
                _quartzScheduler.ScheduleJob(GetJobDetail(alarm), (Trigger)trigger);
            }
        }

        public void RemoveTrigger(Alarm alarm)
        {
            _quartzScheduler.UnscheduleJob(alarm.Name, alarm.Group);
            AlarmList.Remove(alarm.Name);
        }

        public void PauseTrigger(Alarm alarm)
        {
                _quartzScheduler.PauseTrigger(alarm.Name, alarm.Group);
        }

        public int GetTriggerState(Alarm alarm)
        {
            return (int) _quartzScheduler.GetTriggerState(alarm.Name,alarm.Group);
        }

        public void ResumeTrigger(Alarm alarm)
        {
            _quartzScheduler.ResumeTrigger(alarm.Name, alarm.Group);
        }

        public void PauseTriggerGroup(Alarm alarm)
        {
            PauseTriggerGroup(alarm.Group);
        }

        public void PauseTriggerGroup(string groupName)
        {
            //foreach (Alarm alarm in _alarmList.Values)
            //{
            //    if (alarm.Group == groupName)
            //    {
            //        PauseTrigger(alarm);
            //    }
            //}
            _quartzScheduler.PauseTriggerGroup(groupName);
        }

        public void ResumeTriggerGroup(Alarm alarm)
        {
            ResumeTriggerGroup(alarm.Group);
        }
        
        public void ResumeTriggerGroup(string groupName)
        {
            //foreach (Alarm alarm in _alarmList.Values)
            //{
            //    if (alarm.Group == groupName)
            //    {
            //        ResumeTrigger(alarm);
            //    }
            //}
            _quartzScheduler.ResumeTriggerGroup(groupName);
        }

        public void SetSnoozeTrigger(Alarm alarm, int duration)
        {
            throw new NotImplementedException();
        }

        public void SetNextOccurrence(Alarm alarm, DateTime nextOccurrence)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region CreateTrigger shared methods and return types.


        public static Trigger CreateMinutelyTrigger(CreateTriggerArgs createTriggerArgs)
        {
            Trigger trigger = TriggerUtils.MakeMinutelyTrigger();
            trigger.StartTimeUtc = TriggerUtils.GetNextGivenMinuteDate(createTriggerArgs.StartTime, createTriggerArgs.Interval);
            trigger.Name = createTriggerArgs.TriggerName;
            trigger.Group = createTriggerArgs.GroupName;
            return (Trigger)trigger;
        }

        public static Trigger CreateAppointmentTrigger(CreateTriggerArgs createTriggerArgs)
        {
            Trigger trigger = new SimpleTrigger(createTriggerArgs.TriggerName, createTriggerArgs.GroupName, createTriggerArgs.StartTime);
            return (Trigger)trigger;
        }

        public static Trigger CreateDailyTrigger(CreateTriggerArgs createTriggerArgs)
        {
            Trigger trigger = TriggerUtils.MakeDailyTrigger(createTriggerArgs.StartTime.Hour, createTriggerArgs.StartTime.Minute);
            trigger.Name = createTriggerArgs.TriggerName;
            trigger.Group = createTriggerArgs.GroupName;
            return (Trigger)trigger;

        }

        public static Trigger CreateSnoozeTrigger(CreateTriggerArgs createTriggerArgs)
        {
            Trigger trigger = new SimpleTrigger(createTriggerArgs.TriggerName, createTriggerArgs.GroupName, DateTime.UtcNow.AddMinutes(createTriggerArgs.Interval));
            return (Trigger)trigger;
        }

        public static Trigger CreateSecondlyTrigger(CreateTriggerArgs createTriggerArgs)
        {
            Quartz.SimpleTrigger trigger = (SimpleTrigger)TriggerUtils.MakeSecondlyTrigger(createTriggerArgs.Interval);
            trigger.StartTimeUtc = DateTime.Now;
            trigger.Name = createTriggerArgs.TriggerName;
            trigger.Group = createTriggerArgs.GroupName;
            return (Trigger)trigger;
        }
        public static Trigger CreateImmediateTrigger(CreateTriggerArgs createTriggerArgs)
        {
            Quartz.SimpleTrigger trigger = new SimpleTrigger(createTriggerArgs.TriggerName,createTriggerArgs.GroupName,DateTime.UtcNow,null,0,TimeSpan.Zero);
            return (Trigger)trigger;
        }

        #endregion

        public  void Execute(string triggerName)
        {
            if (_alarmList.ContainsKey(triggerName))
            {
                Alarm alarm = _alarmList[triggerName];
                alarm.TriggerHandler();
            }
        }
    }
}
